package com.ecarx.module_vehicle.signal.Model;

import android.car.hardware.property.CarPropertyManager;

import com.ecarx.library_base.BaseApplication;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class SignalModel {

    private static final String XML_TAG_MODULE = "module";
    private static final String XML_TAG_FUNCTION = "function";
    private static final String XML_TAG_WRAPPEDPROPERTYID = "WrappedPropertyId";
    private static final String XML_TAG_AREA_ID = "AreaId";
    private static final String XML_TAG_INPROPERTYVALUE = "InPropertyValue";
    private static final String XML_TAG_DYNAMICINPROPERTYVALUE = "DynamicInPropertyValue";
    private static final String XML_TAG_NAME = "name";
    private static final String XML_TAG_TYPE = "type";
    private static final String XML_TAG_ADAPT_ID = "adaptId";
    private static final String XML_TAG_EDITMAX = "editMax";
    private static final String XML_TAG_EDITMIN = "editMin";
    private static final String XML_TAG_EDITSTEP = "editStep";
    private static final String XML_TAG_AOSP_ID = "aospId";
    private static final String XML_TAG_SHORTNAME = "shortName";
    private static final String XML_TAG_ACCESS = "access";
    private static final String XML_TAG_ICON = "icon";
    private static final String XML_FILE_NAME = "vehiclesignal.xml";

    private static final String ACCESS_WRITE = "write";
    private static final String ACCESS_READ = "read";
    private static final String ACCESS_READ_WRITE = "read_write";

    private static final String ICON_SELECTED_SUFFIX = "_selected";

    private static List<Rate> mRateList;

    private static final Map<String, Integer> mIconMap = new HashMap<>();

    /**
     * 获取回调参数列表
     */
    public static List<Rate> getDefRateList() {
        if (mRateList == null) {
            mRateList = new ArrayList<>();
            mRateList.add(new Rate("0.0F", CarPropertyManager.SENSOR_RATE_ONCHANGE));
            mRateList.add(new Rate("1.0F", CarPropertyManager.SENSOR_RATE_NORMAL));
            mRateList.add(new Rate("5.0F", CarPropertyManager.SENSOR_RATE_UI));
            mRateList.add(new Rate("10.0F", CarPropertyManager.SENSOR_RATE_FAST));
            mRateList.add(new Rate("100.0F", CarPropertyManager.SENSOR_RATE_FASTEST));
        }
        return mRateList;
    }

    /**
     * 图标对应
     */
    public static int getModuleSelectedDrawable(String module) {
        return mIconMap.get(module + ICON_SELECTED_SUFFIX);
    }

    /**
     * 图标对应
     */
    public static int getModuleDrawable(String module) {
        return mIconMap.get(module);
    }

    public static Map<String, List<SignalItem>> initSignalModelFormXML() {
        Map<String, List<SignalItem>> signalItemHashMap = new LinkedHashMap<>();

        InputStream inputStream = null;
        try {
            inputStream = BaseApplication.getInstance().getAssets().open(XML_FILE_NAME);
            DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();

            DocumentBuilder domBuilder = domfac.newDocumentBuilder();
            Document doc = domBuilder.parse(inputStream);
            Element root = doc.getDocumentElement();

            NodeList moduleNode = root.getElementsByTagName(XML_TAG_MODULE);

            if (moduleNode == null) {
                return signalItemHashMap;
            }

            //module节点循环
            for (int i = 0; i < moduleNode.getLength(); i++) {
                List<SignalItem> signalItemList = new ArrayList<>();
                Node book = moduleNode.item(i);
                String moduleName = book.getAttributes().getNamedItem(XML_TAG_NAME).getNodeValue();
                String icon = book.getAttributes().getNamedItem(XML_TAG_ICON).getNodeValue();
                NodeList childNodes = book.getChildNodes();
                int drawable = BaseApplication.getInstance().getResources().getIdentifier(icon, "drawable", BaseApplication.getInstance().getPackageName());
                int selectedDrawable = BaseApplication.getInstance().getResources().getIdentifier(icon + ICON_SELECTED_SUFFIX, "drawable", BaseApplication.getInstance().getPackageName());
                mIconMap.put(moduleName, drawable);
                mIconMap.put(moduleName + ICON_SELECTED_SUFFIX, selectedDrawable);

                int functionLength = childNodes.getLength();

                //function节点循环
                for (int j = 0; j < functionLength; j++) {
                    Node functionNode = childNodes.item(j);
                    if (functionNode == null || functionNode.getNodeType() != Node.ELEMENT_NODE || !XML_TAG_FUNCTION.equals(functionNode.getNodeName())) {
                        continue;
                    }

                    NamedNodeMap nodeAttributes = functionNode.getAttributes();
                    String functionName = getNodeValue(nodeAttributes, XML_TAG_NAME, "");
                    String functionType = getNodeValue(nodeAttributes, XML_TAG_TYPE, "");
                    String access = getNodeValue(nodeAttributes, XML_TAG_ACCESS, ACCESS_READ_WRITE);

                    boolean canGet = access.contains(ACCESS_READ);
                    boolean canSet = access.contains(ACCESS_WRITE);

                    SignalItem signalItem = new SignalItem();
                    signalItem.setModuleName(moduleName);

                    if (functionType.equals("boolean")) {
                        signalItem.getInPropertyValues().add(new InPropertyValue("false",
                                "False",
                                "",
                                "false"));
                        signalItem.getInPropertyValues().add(new InPropertyValue("true",
                                "True",
                                "",
                                "true"));
                    }

                    //function内部节点循环
                    NodeList functionChildNodesList = functionNode.getChildNodes();
                    for (int k = 0; k < functionChildNodesList.getLength(); k++) {
                        Node functionChildNode = functionChildNodesList.item(k);
                        if (functionChildNode == null || functionChildNode.getNodeType() != Node.ELEMENT_NODE) {
                            continue;
                        }

                        String nodeName = functionChildNode.getNodeName();
                        NamedNodeMap attributes = functionChildNode.getAttributes();

                        String name = getNodeValue(attributes, XML_TAG_NAME, "");

                        String adaptId = getNodeValue(attributes, XML_TAG_ADAPT_ID, "");

                        String aospId = getNodeValue(attributes, XML_TAG_AOSP_ID, "");

                        String shortName = getNodeValue(attributes, XML_TAG_SHORTNAME, "");

                        if (XML_TAG_AREA_ID.equals(nodeName)) {
                            signalItem.getAreaIdList().add(new AreaId(name, shortName, adaptId, aospId));

                        } else if (XML_TAG_WRAPPEDPROPERTYID.equals(nodeName)) {
                            signalItem.setWrappedPropertyId(new WrappedPropertyId(name, functionName, adaptId, aospId, functionType, canSet, canGet));

                        } else if (XML_TAG_INPROPERTYVALUE.equals(nodeName)) {

                            signalItem.getInPropertyValues().add(new InPropertyValue(name,
                                    shortName,
                                    adaptId,
                                    aospId
                            ));
                        } else if (XML_TAG_DYNAMICINPROPERTYVALUE.equals(nodeName)) {
                            String editMin = getNodeValue(attributes, XML_TAG_EDITMIN, "");
                            String editMax = getNodeValue(attributes, XML_TAG_EDITMAX, "");
                            String editStep = getNodeValue(attributes, XML_TAG_EDITSTEP, "");

                            float value = Float.parseFloat(editMin);
                            float max = Float.parseFloat(editMax);
                            float step = Math.max(Integer.parseInt(editStep), 1);
                            boolean isIntValue = functionType.equals("int");
                            while (value <= max) {
                                String valueS = isIntValue ? String.valueOf((int) value) : String.valueOf(value);
                                signalItem.getInPropertyValues().add(new InPropertyValue(valueS,
                                        valueS,
                                        "",
                                        valueS
                                ));
                                value += step;
                            }
                        }
                    }
                    signalItem.getRateList().addAll(getDefRateList());
                    signalItemList.add(signalItem);
                }
                signalItemHashMap.put(moduleName, signalItemList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return signalItemHashMap;
    }

    private static String getNodeValue(NamedNodeMap attributes, String tag, String def) {
        Node editStepNode = attributes.getNamedItem(tag);
        return editStepNode != null ? editStepNode.getNodeValue() : def;
    }
}
